using UnityEngine;
using System.Collections.Generic;

namespace Neatly.UI
{
    [RequireComponent(typeof(RectTransform))]
    public class NParticleSystem : MonoBehaviour
    {

        #region Inspector
        public bool showParticleSystem = false;
        public bool showEmission = false;
        public bool showShape = false;
        public bool showSize = false;
        public bool showColor = false;
        public bool showRotate = false;
        public bool showVelocityOverLifeTime = false;
        public bool showForceOverLifeTime = false;

        public bool enableSize = false;
        public bool enableColor = false;
        public bool enableRotate = false;
        public bool enableVelocity = false;
        public bool enableForce = false;
        #endregion

        public enum Shape
        {
            Rect,
            Circle,
        }

        public enum EmissionShapeType
        {
            Sector,
            Circle,
        }
        #region ParticleSystem
        [SerializeField]
        private Sprite m_Sprite;
        [SerializeField]
        private Material m_Material;
        [SerializeField]
        private Shape m_ShapeType;
        [SerializeField]
        [Range(0, 99)]
        private float m_StartDelay = 0;
        [SerializeField]
        [Range(0, 99)]
        private float m_StartLifetime = 5;
        [SerializeField]
        [Range(0, 1)]
        private float m_RandLifeRatio = 0;
        [SerializeField]
        private float m_StartSpeed = 1;
        [SerializeField]
        [Range(0, 1)]
        private float m_RandSpeedRatio = 0;
        [SerializeField]
        private Vector2 m_StartSize = Vector2.one * 20;
        [SerializeField]
        private Color m_Color = Color.white;
        [SerializeField]
        [Range(1, 2000)]
        private int m_MaxParticles = 10;

        private float m_SizeMin;
        private float m_SizeMax;
        #endregion

        #region Emission
        //Count per Time
        [SerializeField]
        private float m_RateOverTime = 2;
        // Please wait... 
        [SerializeField]
        private float m_RateOverDistance;
        //base Time.
        private const float m_EmissionBaseTime = 1;
        private float m_EmissionDeltaTime;
        private float m_EmissionTotalTime = 0;
        #endregion

        #region Shape
        [SerializeField]
        private EmissionShapeType m_EmissionShape = EmissionShapeType.Sector;
        public EmissionShapeType EmissionEmissionShape { get { return m_EmissionShape; } }
        [SerializeField]
        [Range(0, 360)]
        private int m_Angle;
        #endregion

        #region Velocity
        [SerializeField]
        private Vector2 m_Velocity = Vector2.zero;
        [SerializeField]
        [Range(0, 1)]
        private float m_RandVelocityRatio = 0;
        #endregion

        #region Force
        [SerializeField]
        private Vector2 m_Force = Vector2.zero;
        [SerializeField]
        [Range(0, 1)]
        private float m_RandForceRatio = 0;
        #endregion

        #region Color
        [SerializeField]
        private Color m_FinalColor = Color.white;
        #endregion

        #region Size
        [SerializeField]
        private Vector2 m_FinalSize = Vector2.zero;
        #endregion

        #region Property
        private Vector2 m_Position;
        private RectTransform m_RectTransform;
        private List<EffectImage> m_ParticleList = new List<EffectImage>();
        private List<EffectImage> m_CacheParticleList = new List<EffectImage>();

        private float m_HalfWidth;
        private float m_HalfHeight;
        private int m_HalfAngle;
        private float m_LifeMin;
        private float m_LifeMax;
        private float m_SpeedMin;
        private float m_SpeedMax;

        private Vector2 m_RandPosition = Vector2.zero;
        private Vector2 m_RandDirect = Vector2.zero;
        private float m_RandLifeTime = 0;
        private float m_RandSpeed = 0;
        private Vector2 m_RandVelocity = Vector2.zero;
        private Vector2 m_RandForce = Vector2.zero;

        private byte m_CurrentCount;
        #endregion

        void Start()
        {
            Init();
        }

        void Init()
        {
            if (m_EmissionShape == EmissionShapeType.Circle)
            {
                m_Angle = 360;
            }
            m_RectTransform = transform as RectTransform;
            m_Position = m_RectTransform.anchoredPosition;
            m_HalfWidth = m_RectTransform.rect.width / 2;
            m_HalfHeight = m_RectTransform.rect.height / 2;
            m_HalfAngle = m_Angle / 2;
            m_LifeMin = m_StartLifetime - m_StartLifetime * m_RandLifeRatio;
            m_LifeMax = m_StartLifetime + m_StartLifetime * m_RandLifeRatio;
            m_SpeedMin = m_StartSpeed - m_StartSpeed * m_RandSpeedRatio;
            m_SpeedMax = m_StartSpeed + m_StartSpeed * m_RandSpeedRatio;
            m_EmissionDeltaTime = m_EmissionBaseTime / m_RateOverTime;
        }

        void DoEmission(float deltaTime)
        {
            m_EmissionTotalTime += deltaTime;
            if (m_EmissionTotalTime <= m_EmissionDeltaTime) return;
            //get sprite from cache
            var effectSprite = GetEffectSprite();
            // in max
            if (effectSprite == null) return;
            effectSprite.Show();
            //Random position
            RandPosDirectSpeed();
            effectSprite.SetStartInfo(m_RandPosition, m_StartSize, m_RandLifeTime, m_RandDirect, m_RandSpeed);
            //set sprite and material , Color
            effectSprite.SetSpriteInfo(m_Sprite, m_Material, m_Color);

            if (enableVelocity)
            {
                effectSprite.AddVelocity(m_RandVelocity);
            }
            if (enableForce)
            {
                effectSprite.AddForce(m_RandForce);
            }
            if (enableColor)
            {
                effectSprite.AddColorTween(m_FinalColor);
            }
            if (enableSize)
            {
                effectSprite.AddSizeTween(m_FinalSize);
            }
            m_EmissionTotalTime = 0;
            m_ParticleList.Add(effectSprite);
        }
        
        private EffectImage GetEffectSprite()
        {
            EffectImage effectImage;
            if (m_CacheParticleList.Count > 0)
            {
                int index = m_CacheParticleList.Count - 1;
                effectImage = m_CacheParticleList[index];
                m_CacheParticleList.RemoveAt(index);
                return effectImage;
            }
            if (m_CurrentCount >= m_MaxParticles) return null;
            m_CurrentCount++;
            effectImage = NParticlePool.Instance.Create();
            effectImage.transform.SetParent(transform);
            effectImage.rectTransform.SetAnchoredPosition3DOne(0);
            effectImage.transform.SetLocalScaleOne(0);
            return effectImage;
        }

        /// <summary>
        /// Reset Emission Position.
        /// </summary>
        /// <returns></returns>
        private void RandPosDirectSpeed()
        {
            float posX = Random.Range(- m_HalfWidth, m_HalfWidth);
            float posY = Random.Range(- m_HalfHeight, m_HalfHeight);
            m_RandPosition.x = posX;
            m_RandPosition.y = posY;

            int randomAngle = Random.Range(-m_HalfAngle, m_HalfAngle);
            float directX = Mathf.Sin(Mathf.Deg2Rad * randomAngle) * 10;
            float directY = Mathf.Cos(Mathf.Deg2Rad * randomAngle) * 10;
            m_RandDirect.x = directX;
            m_RandDirect.y = directY;
            m_RandLifeTime = Random.Range(m_LifeMin, m_LifeMax);
            m_RandSpeed = Random.Range(m_SpeedMin, m_SpeedMax);
            if (enableVelocity)
            {
                float ratioX = m_Velocity.x * m_RandVelocityRatio;
                float ratioY = m_Velocity.y * m_RandVelocityRatio;
                m_RandVelocity.x = Random.Range(m_Velocity.x - ratioX, m_Velocity.x + ratioX);
                m_RandVelocity.y = Random.Range(m_Velocity.y - ratioY, m_Velocity.y + ratioY);
            }
            if (enableForce)
            {
                float ratioX = m_Force.x * m_RandForceRatio;
                float ratioY = m_Force.y * m_RandForceRatio;
                m_RandForce.x = Random.Range(m_Force.x - ratioX, m_Force.x + ratioX);
                m_RandForce.y = Random.Range(m_Force.y - ratioY, m_Force.y + ratioY);
            }
        }

        bool m_IsPause = false;
        public void Pause()
        {
            m_IsPause = true;
        }

        public void Resume()
        {
            m_IsPause = false;
        }

        void Update()
        {
            if (m_IsPause) return;
            for (int i = m_ParticleList.Count - 1; i >= 0; i--)
            {
                var effectSprite = m_ParticleList[i];
                bool isFinish = effectSprite.ParticleUpdate(Time.deltaTime);
                if (isFinish)
                {
                    effectSprite.Hide();
                    m_ParticleList.RemoveAt(i);
                    m_CacheParticleList.Add(effectSprite);
                }
            }
            DoEmission(Time.deltaTime);
        }

        //        void OnEnable()
        //        {
        //            Reset();
        //        }
        //
        //        void OnDisable()
        //        {
        //            for (int i = m_CacheParticleList.Count-1; i >=0; i--)
        //            {
        //                var effectSprite = m_CacheParticleList[i];
        //                m_CacheParticleList.RemoveAt(i);
        //                SDParticlePool.Instance.Recycle(effectSprite);
        //            }
        //            for (int i = m_ParticleList.Count - 1; i >= 0; i--)
        //            {
        //                var effectSprite = m_ParticleList[i];
        //                m_ParticleList.RemoveAt(i);
        //                SDParticlePool.Instance.Recycle(effectSprite);
        //            }
        //            Reset();
        //        }

        //        void Reset()
        //        {
        //            m_CurrentCount = 0;
        //            m_EmissionTotalTime = 0;
        //        }
        //        

        void OnDrawGizmosSelected()
        {
        }

#if UNITY_EDITOR
        /// <summary>
        /// Reset System and Restart. Only in Editor
        /// </summary>
        public void Restart()
        {
            //
            for (int i = m_ParticleList.Count - 1; i >= 0; i--)
            {
                var effectSprite = m_ParticleList[i];
                m_ParticleList.RemoveAt(i);
                DestroyImmediate(effectSprite.gameObject);
            }
            for (int i = m_CacheParticleList.Count - 1; i >= 0; i--)
            {
                var effectSprite = m_CacheParticleList[i];
                m_CacheParticleList.RemoveAt(i);
                DestroyImmediate(effectSprite.gameObject);
            }
            Init();
        }
#endif
    }

}